/**
 * Copyright (c) 2015-2030 by Beijing Yanlight Co., Ltd.
 * All rights reserved.
 */
package com.yanlight.util;

import java.nio.charset.Charset;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

/**
 * 
 * @author haolw
 * @time 2017/12/08
 */
class AESEncryption {
	private static AESEncryption instrance = new AESEncryption();
	private final Charset CHARSET = Charset.forName("UTF-8");
	private final String KEY_GENERATION = "PBKDF2WithHmacSHA1";
	private final String SECURE_ALG = "SHA1PRNG";
	private final String PADDING = "/CBC/PKCS5Padding";
	private final String ALGORITHM = "AES";
	private final String TRANSFORMATION = ALGORITHM + PADDING;
	private final int ITERATION_COUNT = 16;
	private final int KEY_LENGTH = 128;
	private final String key = "dGtIUEFuXwZRntQU";
	private final String salt = "ynukaNEZMzRSPeWk";
	private final String iv = "raitxuCQsYQvLfXG";
	private SecretKey secretKey;
	private AlgorithmParameterSpec algParamSpec;
	private SecureRandom random;

	private AESEncryption() {
		initialization();
	};

	public static AESEncryption getInstrance() {
		return instrance;
	}

	private void initialization() {
		try {
			char[] keys = key.toCharArray();
			byte[] salts = salt.getBytes(CHARSET);
			byte[] ivs = iv.getBytes(CHARSET);
			random = SecureRandom.getInstance(SECURE_ALG);
			random.setSeed(salts);
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_GENERATION);
			PBEKeySpec pbeKeySpec = new PBEKeySpec(keys, salts, ITERATION_COUNT, KEY_LENGTH);
			byte[] encoded = keyFactory.generateSecret(pbeKeySpec).getEncoded();
			secretKey = new SecretKeySpec(encoded, ALGORITHM);
			algParamSpec = new IvParameterSpec(ivs);
		} catch (Exception e) {
			throw new IllegalArgumentException(e);
		}
	};

	public String encrypt(String src) {
		try {
			return encrypt(src.getBytes(CHARSET));
		} catch (Exception e) {
			throw new IllegalArgumentException(e);
		}
	}

	public String encrypt(byte[] src) {
		try {
			return Base64.encodeBase64URLSafeString(encryptByte(src));
		} catch (Exception e) {
			throw new IllegalArgumentException(e);
		}
	}

	private byte[] encryptByte(byte[] src) {
		try {
			return cipher(src, Cipher.ENCRYPT_MODE);
		} catch (Exception e) {
			throw new IllegalArgumentException(e);
		}
	}

	public String decrypt(String src) {
		try {
			return decrypt(src.getBytes(CHARSET));
		} catch (Exception e) {
			throw new IllegalArgumentException(e);
		}
	}

	public String decrypt(byte[] src) {
		try {
			return new String(decryptByte(Base64.decodeBase64(src)), CHARSET);
		} catch (Exception e) {
			throw new IllegalArgumentException(e);
		}
	}

	private byte[] decryptByte(byte[] src) {
		return cipher(src, Cipher.DECRYPT_MODE);
	}

	private byte[] cipher(byte[] content, int mode) {
		try {
			Cipher cipher = Cipher.getInstance(TRANSFORMATION);
			cipher.init(mode, secretKey, algParamSpec, random);
			return cipher.doFinal(content);
		} catch (Exception e) {
			throw new IllegalArgumentException(e);
		}
	}

}
